/**
 * @Description:  函数
 */
/**
 *  默认参数值
 */
//传统方式
function fn1(str1) {
  str1 = (typeof str1 !== 'undefined') ? str1 : 'funlee'
  console.log('argument is ' + str1) 
}
fn1()
//ES6
function fn1(str1 = 'funlee') {
  console.log('argument is ' + str1) 
}
fn1()
//-------------------------------------------------------------------------------------------
/**
 *  在已指定默认值的参数后可以继续声明无默认值参数
 *  
 */
function request(url,timeout = 2000,callback) {
  //code
  console.log(timeout)
}
/**
 *  上述这种情况下，只有当不为第二个参数传入值或主动为第二个参数传入undefined时才会使用timeout的默认值
 */
var test//undefined
request('/foo',test,function(body){
  doSomething(body)
})
/**
 *  对于默认参数值，null是一个合法值
 */
request('/foo',null,function(body){ //timeout = null,即没有使用timoout的默认值
  doSomething(body)
})
//-------------------------------------------------------------------------------------------
/**
 *  默认参数值对arguments的影响
 */
function mixArgs(first,second) {
  console.log(first === arguments[0])
  console.log(second === arguments[1])
  first = 'c'
  second = 'd'
  console.log(first === arguments[0])
  console.log(second === arguments[1])
}
mixArgs('c','d') //全是true，非严格模式下，命名参数的变化会同步更新到arguments对象中
                //严格模式，无论参数怎么变化，arguments对象不再随之改变
/**
 *  在ES6中，如果一个参数使用了默认参数值
 *  arguments对象的行为将与ES5的严格模式保持一致
 */
function mixArgs(first,second = 'abc') {
  console.log(arguments)
  console.log(first === arguments[0])
  console.log(second === arguments[1])
  first = 'c'
  second = 'd'
  console.log(first === arguments[0])
  console.log(second === arguments[1])
}
mixArgs('a')
//------------------------------------------------------------------------------------------
/**
 *  默认参数表达式
 */
let value = 5
function getValue() {
  return value++
}
function add(num1,num2 = getValue()) {
  console.log('num1 + num2 = ' + (num1 + num2))
}
add(1,2)
add(1)
add(1)
//后定义的参数，可以访问先定义的参数
function getValue(value) {
  return value + 5
}
function add(num1,num2 = getValue(num1)) {
  console.log('num1 + num2 = ' + (num1 + num2))
}
add(1,2)
add(1)
add(1)
//----------------------------------------------------------------------------------
/**
 *  默认参数的临时死区(TDZ)
 */

function add(num1 = num2,num2) {
  console.log(num1 + num2)
}
add(1,2)
var num;
add(num,1) //let num1 = num2;let num2 = 1;
//----------------------------------------------------------------------------------
/**
 *  ES5无命名参数
 *  类似Underscore.js库中的pick方法
 *  返回一个给定对象的副本，包含原始对象属性的特定子集
 */
function pick(object) {
  let result = Object.create(null);
  //从第二个参数开始
  for(let i = 1,len = arguments.length;i < len;i++) {
    result[arguments[i]] = object[arguments[i]];
  }
  return result;
}
let book = {
  title:'Understanding ES6',
  author:'Zakas',
  year:2016
}
let bookData = pick(book,'author','year')

console.log(bookData.author)
console.log(bookData.year)
//----------------------------------------------------------------------------------
/**
 *  ES6 不定参数解决上述问题
 *  arguments对象包含了所有传入函数的参数
 *  不定参数使用限制：
 *  1.每个函数最多只能声明一个不定参数，而且一定要放在所有参数的末尾
 *  2.不定参数不能用于对象字面量setter之中（因为setter参数有且只能有一个）
 */
function pick(object,...keys) {
  console.log(keys)
  let result = Object.create(null);
  for(let i = 0,len = keys.length;i < len;i++) {
    result[keys[i]] = object[keys[i]]
  }
  return result
}
let book = {
  title:'Understanding ES6',
  author:'Zakas',
  year:2016
}
let bookData = pick(book,'author','year')

console.log(bookData)
console.log(pick.length)//1,函数的length属性统计的是函数命名参数的数量，不定参数的加入不会影响length属性的值
//----------------------------------------------------------------------------------
/**
 *  增强 Function构造函数
 */
var fn = new Function('num1','console.log("this is a test")')
fn(5)

var fn = new Function('...args','console.log(arguments)')
fn('a','b','c')
//----------------------------------------------------------------------------------
//ES5求取最大值
Math.max(10,20,30,40);

let values = [10,20,30,40,50]
console.log(Math.max.apply(Math,values)) //难以看懂
/**
 *  展开运算符
 *  解决上述问题：求取数组最大值
 */
let values = [12,6,486,3,1,6,33]
console.log(Math.max(...values))

//限定Math.max()返回的最小值

let values = [10,20,45,33,60]

console.log(Math.max(...values,70))//最大值不能超过70
console.log(Math.min(...values,5))//最小值不能超过5


//将来你会发现，在大多数使用apply方法的情况下，展开运算符可能是一个更合适的方案

//这个就厉害了，但是我apply都用得少
